package com.dhcc.sdc.task;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.dhcc.cdc.busi.entity.CdcDictionaryEntity;
import com.dhcc.cdc.busi.service.ICdcDictionaryService;
import com.dhcc.core.framework.util.CommonUtil;
import com.dhcc.core.framework.util.DateUtil;
import com.dhcc.sdc.base.dao.ContraindicationItemRuleMapper;
import com.dhcc.sdc.base.dao.ContraindicationMapper;
import com.dhcc.sdc.base.dao.ContraindicationQcentityMapper;
import com.dhcc.sdc.base.entity.ContraindicationEntity;
import com.dhcc.sdc.base.entity.ContraindicationItemEntity;
import com.dhcc.sdc.base.entity.ContraindicationItemRuleEntity;

import com.dhcc.sdc.base.entity.ContraindicationQcentity;
import com.dhcc.sdc.base.service.IContraindicationItemService;
import com.dhcc.sdc.base.service.IContraindicationService;
import com.dhcc.sdc.busi.dao.SdcBusiContraindicationDtlMapper;
import com.dhcc.sdc.busi.dao.SdcBusiContraindicationMapper;
import com.dhcc.sdc.busi.entity.SdcBusiContraindicationDtlEntity;
import com.dhcc.sdc.busi.entity.SdcBusiContraindicationEntity;
import com.dhcc.sdc.busi.function.GetSdcValueSrv;
import com.dhcc.sds.busi.entity.SdsQcincaseEntity;
import com.dhcc.sds.busi.service.ISdsQcincaseService;
import com.dhcc.sds.standard.dao.SdsStandSourceFieldMapper;
import com.dhcc.sds.standard.dao.SdsStandSourceMapper;
import com.dhcc.sds.standard.entity.SdsStandSourceEntity;
import com.dhcc.sds.standard.entity.SdsStandSourceFieldEntity;
import com.googlecode.aviator.AviatorEvaluator;
import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.MapContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Description:禁忌症规则定时任务
 * @ClassName:  ContraindicationTask
 * @date:2022年11月3日 下午3:45:16
 * @author: zhangdc
 */
@Service("contraindicationTask")
public class ContraindicationTask {

    @Autowired
    private ISdsQcincaseService sdsQcincaseService;
    @Autowired
    private ICdcDictionaryService cdcDictionaryService;
    @Autowired
    private IContraindicationItemService contraindicationItemService;
    @Autowired
    private GetSdcValueSrv getSdcValueSrv;
    @Resource
    private SdsStandSourceMapper sdsStandSourceMapper;
    @Resource
    private SdsStandSourceFieldMapper sdsStandSourceFieldMapper;
    @Resource
    private ContraindicationItemRuleMapper contraindicationItemRuleMapper;
    @Resource
    private ContraindicationMapper contraindicationMapper;
    @Resource
    private SdcBusiContraindicationMapper sdcBusiContraindicationMapper;
    @Resource
    private SdcBusiContraindicationDtlMapper sdcBusiContraindicationDtlMapper;
    @Autowired
    private IContraindicationService contraindicationService;

    //小括号及其里面内容
    private static String p1 = "\\(.*?\\)";

    public void autoTaskForContraindication(){
        //就诊状态:在院
        CdcDictionaryEntity admStatus = cdcDictionaryService.queryByTypeCodeAndCode("PatData", "bus_adm_status", "A");
        //查询入组在院患者
        List<SdsQcincaseEntity> sdsQcincaseEntities = sdsQcincaseService.selectContraindicationByAdmStatus(admStatus.getId());
        a:for (SdsQcincaseEntity sdsQcincaseEntity : sdsQcincaseEntities){
            /*List<ContraindicationEntity> contraindicationEntities = contraindicationMapper.selectList(new EntityWrapper<ContraindicationEntity>()
                    .eq("entity_id", sdsQcincaseEntity.getEntityId()));*/
            List<ContraindicationEntity> contraindicationEntities = contraindicationService.getByQcincaseId(sdsQcincaseEntity.getId());
            b:for (ContraindicationEntity contraindicationEntity : contraindicationEntities){
                //临床审核不用跑规则
                SdcBusiContraindicationEntity busiContraindicationEntity = new SdcBusiContraindicationEntity();
                busiContraindicationEntity.setEpisodeId(sdsQcincaseEntity.getEpisodeId());
                busiContraindicationEntity.setContraindicationId(contraindicationEntity.getId());
                busiContraindicationEntity = sdcBusiContraindicationMapper.selectOne(busiContraindicationEntity);
                if ((busiContraindicationEntity != null) && (busiContraindicationEntity.getResult() != null)){
                    continue b;
                }

                Integer res = conItemResult(sdsQcincaseEntity.getEpisodeId(), sdsQcincaseEntity.getEntityId(), contraindicationEntity.getId());
                if (res == 1){
                    SdcBusiContraindicationEntity sdcBusiContraindicationEntity = new SdcBusiContraindicationEntity();
                    sdcBusiContraindicationEntity.setEpisodeId(sdsQcincaseEntity.getEpisodeId());
                    sdcBusiContraindicationEntity.setContraindicationId(contraindicationEntity.getId());
                    sdcBusiContraindicationEntity = sdcBusiContraindicationMapper.selectOne(sdcBusiContraindicationEntity);
                    if (sdcBusiContraindicationEntity == null){
                        //insert
                        sdcBusiContraindicationEntity = new SdcBusiContraindicationEntity();
                        sdcBusiContraindicationEntity.setEpisodeId(sdsQcincaseEntity.getEpisodeId());
                        sdcBusiContraindicationEntity.setContraindicationId(contraindicationEntity.getId());
                        sdcBusiContraindicationEntity.setResultAuto(res);
                        sdcBusiContraindicationEntity.setUpdateDate(new Date());
                        sdcBusiContraindicationEntity.insert();
                    }else {
                        //update
                        sdcBusiContraindicationEntity.setResultAuto(res);
                        sdcBusiContraindicationEntity.setUpdateDate(new Date());
                        sdcBusiContraindicationEntity.updateAllColumnById();
                    }
                }
            }

        }
    }

    public Integer conItemResult(Long episodeId, Long entityId, Long conId){
        Integer res = 0;
        List<Integer> values = new ArrayList<>();
        List<ContraindicationItemEntity> contraindicationItemEntities = contraindicationItemService.selectList(new EntityWrapper<ContraindicationItemEntity>()
                .eq("contraindication_id", conId));
        for (ContraindicationItemEntity contraindicationItemEntity : contraindicationItemEntities){
            if (!StringUtils.isEmpty(contraindicationItemEntity.getExpression())){
                //触发的关键词来源
                String keyWordsfrom = getKeyWordsfrom(contraindicationItemEntity.getExpression());

                //条目规则
                Map<String, Object> resultMap  = ruleExpressionParse(contraindicationItemEntity.getExpression(), episodeId, entityId);
                boolean value = (boolean) resultMap.get("result");
                String keywords = resultMap.get("keywords").toString();
                if (value){
                    Integer i = 1;
                    values.add(i);
                    SdcBusiContraindicationDtlEntity sdcBusiContraindicationDtlEntity = new SdcBusiContraindicationDtlEntity();
                    sdcBusiContraindicationDtlEntity.setEpisodeId(episodeId);
                    sdcBusiContraindicationDtlEntity.setContraindicationId(conId);
                    sdcBusiContraindicationDtlEntity.setItemId(contraindicationItemEntity.getId());
                    sdcBusiContraindicationDtlEntity = sdcBusiContraindicationDtlMapper.selectOne(sdcBusiContraindicationDtlEntity);
                    if (sdcBusiContraindicationDtlEntity == null){
                        sdcBusiContraindicationDtlEntity = new SdcBusiContraindicationDtlEntity();
                        sdcBusiContraindicationDtlEntity.setEpisodeId(episodeId);
                        sdcBusiContraindicationDtlEntity.setContraindicationId(conId);
                        sdcBusiContraindicationDtlEntity.setItemId(contraindicationItemEntity.getId());
                        sdcBusiContraindicationDtlEntity.setKeyWords(keywords);
                        sdcBusiContraindicationDtlEntity.setMannul(0);
                        sdcBusiContraindicationDtlEntity.setStatus(1);
                        sdcBusiContraindicationDtlEntity.setKeyWordsfrom(keyWordsfrom);
                        sdcBusiContraindicationDtlEntity.setTriggerDate(new Date());
                        sdcBusiContraindicationDtlEntity.setUpdateDate(new Date());
                        sdcBusiContraindicationDtlEntity.insert();
                    }else {
                        if (sdcBusiContraindicationDtlEntity.getMannul()!=1) {// 手动确认的不再更新
                            sdcBusiContraindicationDtlEntity.setKeyWords(keywords);
                            sdcBusiContraindicationDtlEntity.setMannul(0);
                            sdcBusiContraindicationDtlEntity.setStatus(1);
                            sdcBusiContraindicationDtlEntity.setKeyWordsfrom(keyWordsfrom);
                            sdcBusiContraindicationDtlEntity.setUpdateDate(new Date());
                            sdcBusiContraindicationDtlEntity.updateAllColumnById();
                        }
                    }
                }
            }
        }

        for (Integer value : values){
            if (value == 1){
                res = 1;
                break;
            }
        }

        return res;
    }

    private Map<String, Object> ruleExpressionParse(String expreStr, Long episodeId, Long entityId){
        Map<String, Object> resultMap = new HashMap<>();
        String expreStrBak = expreStr;
        // 查找规则公式小括号以内的规则代码
        Pattern p = Pattern.compile(p1);
        Matcher m = p.matcher(expreStr);

        String keyWords = "";
        // 遍历找到的所有括号
        while (m.find()){
            String ruleCode = m.group().substring(1, m.group().length() - 1);

            String ruleVal;
            try {
                ContraindicationItemRuleEntity contraindicationItemRuleEntity = new ContraindicationItemRuleEntity();
                contraindicationItemRuleEntity.setExpCode(ruleCode);
                contraindicationItemRuleEntity = contraindicationItemRuleMapper.selectOne(contraindicationItemRuleEntity);

                ruleVal = handleItemRule(contraindicationItemRuleEntity, episodeId, entityId);
                // 如果规则值是unknown的，代表不是正常返回，这时表达式的“默认值”应具体判断
                if ("unknown".equals(ruleVal)) {
                    if (m.start() != 0 && expreStrBak.substring(m.start()-1, m.start()).equals("!")) {
                        ruleVal = "true";
                    } else {
                        ruleVal = "false";
                    }
                }
                if (Objects.equals(ruleVal, "true")) {
                    keyWords += contraindicationItemRuleEntity.getRuleDesc() + "θ";
                }

            } catch (Exception e) {
                resultMap.put("result", false);
                resultMap.put("keywords", "");
                return resultMap;
            }
            expreStr = expreStr.replace(m.group(), ruleVal);
        }
        // 将表达式中的大括号中括号替换为小括号，以及其他其他字符替换为可执行字符
        expreStr = expreStr.replace("{", "(").replace("}", ")");
        expreStr = expreStr.replace("[", "(").replace("]", ")");

        boolean result =  (boolean) AviatorEvaluator.execute(expreStr);

        resultMap.put("result", result);
        resultMap.put("keywords", keyWords);
        return resultMap;
    }

    //处理禁忌症条目匹配规则
    private String handleItemRule(ContraindicationItemRuleEntity contraindicationItemRuleEntity, Long episodeId, Long entityId){
        String ruleVal = "unknown";
        String res1 ;
        String res2 ;
        if (contraindicationItemRuleEntity == null) {
            return ruleVal;
        }
        // 取值为空时规则默认值
        int defaultValue = contraindicationItemRuleEntity.getDefaultValue();
        // 运算类型
        String ruleType = "";
        if (contraindicationItemRuleEntity.getRuleType() != null) {
            ruleType = contraindicationItemRuleEntity.getRuleType();
        }
        String ruleExpreStr = "";
        Long sourceId1 = contraindicationItemRuleEntity.getDataSource1();
        String sourceOperator1 = contraindicationItemRuleEntity.getOperator1();
        if (CommonUtil.isEmpty(sourceId1)) {
            return ruleVal;
        }
        res1 = String.valueOf(handleGetValue(episodeId, sourceId1, contraindicationItemRuleEntity.getDataSourceItem1(), contraindicationItemRuleEntity.getParam1()));
        if (CommonUtil.isEmpty(res1)) {
            if (CommonUtil.isNotEmpty(defaultValue)) {
                if(defaultValue == 1){
                    ruleVal = "true";
                } else {
                    ruleVal = "false";
                }
            }
            return ruleVal;
        }
        res1 = modelRuleValue(res1, ruleType);
        if (sourceOperator1.contains("\"")||sourceOperator1.contains("\'")||sourceOperator1.contains("‘")||sourceOperator1.contains("“")) {
            sourceOperator1 = sourceOperator1.replace("‘", "\'").replace("’", "\'");
            sourceOperator1 = sourceOperator1.replace("“", "\"").replace("”", "\"");
            res1 = "\""+res1+"\"";
        }
        ruleExpreStr = res1 + sourceOperator1;


        Long sourceId2 = contraindicationItemRuleEntity.getDataSource2();
        String sourceOperator2 = contraindicationItemRuleEntity.getOperator2();
        if (sourceId2 != null){
            res2 = (String) handleGetValue(episodeId, sourceId2, contraindicationItemRuleEntity.getDataSourceItem2(), contraindicationItemRuleEntity.getParam2());
            if (CommonUtil.isEmpty(res2)) {
                if (CommonUtil.isNotEmpty(defaultValue)) {
                    if(defaultValue == 1){
                        ruleVal = "true";
                    } else {
                        ruleVal = "false";
                    }
                }
                return ruleVal;
            }
            res2 = modelRuleValue(res2, ruleType);
            if (sourceOperator2.contains("\"")||sourceOperator2.contains("\'")||sourceOperator2.contains("‘")||sourceOperator2.contains("“")) {
                sourceOperator2 = sourceOperator2.replace("‘", "\'").replace("’", "\'");
                sourceOperator2 = sourceOperator2.replace("“", "\"").replace("”", "\"");
                res2 = "\""+res2+"\"";
            }
            ruleExpreStr += res2 + sourceOperator2;
        }

        // 运行表达式结果且返回
        JexlEngine engine = new JexlEngine();
        JexlContext context = new MapContext();
        Expression expression = engine.createExpression(ruleExpreStr);
        ruleVal = expression.evaluate(context).toString();

        return ruleVal;
    }

    private Object handleGetValue(Long episodeId, Long dataSourceId, Long dataSourceItemId, String param){
        Object res = "";
        SdsStandSourceEntity source = sdsStandSourceMapper.selectById(dataSourceId);
        SdsStandSourceFieldEntity sourceFieldEntity = sdsStandSourceFieldMapper.selectById(dataSourceItemId);
        switch (source.getSourceDesc()) {
            case "电子病历":
                //语义分析
                res = getSdcValueSrv.EmrInfo(episodeId, param, sourceFieldEntity.getFieldCode());
                break;
            case "评估":
                res = getSdcValueSrv.Assessment(episodeId, param, sourceFieldEntity.getFieldCode());
                break;
            case "就诊信息":
                res = getSdcValueSrv.BaseInfoData(episodeId, param, sourceFieldEntity.getFieldCode());
                break;
            case "诊断信息":
                res = getSdcValueSrv.DiagInfo(episodeId, param, sourceFieldEntity.getFieldCode());
                break;
            case "患者医嘱信息":
                res = getSdcValueSrv.OrderInfoData(episodeId, param, sourceFieldEntity.getFieldCode());
                break;
            case "生命体征":
                res = getSdcValueSrv.NurInfo(episodeId, param, sourceFieldEntity.getFieldCode());
                break;
            case "手术信息":
                res = getSdcValueSrv.OperInfo(episodeId, param, sourceFieldEntity.getFieldCode());
                break;
            case "护理措施":
                res = getSdcValueSrv.NursingMeasures(episodeId, param, sourceFieldEntity.getFieldCode());
                break;
            case "患者送检报告信息":
                res = getSdcValueSrv.LisInfoData(episodeId, param, sourceFieldEntity.getFieldCode());
                break;
            case "检验结果信息":
                res = getSdcValueSrv.LisItemInfoData(episodeId, param, sourceFieldEntity.getFieldCode());
                break;
            case "检查医嘱+诊断结果信息":
                res = getSdcValueSrv.RisInfoData2(episodeId, param, sourceFieldEntity.getFieldCode());
                break;
            case "检查项目结果信息":
                res = getSdcValueSrv.RisItemInfoData(episodeId, param, sourceFieldEntity.getFieldCode());
                break;
            case "常用短语":
                res = getSdcValueSrv.UsefulExpressions(episodeId, param, sourceFieldEntity.getFieldCode());
                break;
        }
        return res;
    }

    private List<String> handleRuleExpressions(String ruleExpressions) {
        //小括号及其里面内容
        String p1 = "\\(.*?\\)";
        List<String> res = new ArrayList<>();
        Pattern p = Pattern.compile(p1);
        Matcher m = p.matcher(ruleExpressions);
        while (m.find()){
            String ruleExpression = m.group().substring(1, m.group().length() - 1);
            res.add(ruleExpression);
        }
        return res;
    }

    /**
     * 返回值改造
     *
     * @param bfVal
     * @param ruleType
     * @return
     */
    private String modelRuleValue(String bfVal, String ruleType) {
        String afVal = "";
        if (CommonUtil.isEmpty(bfVal)) {
            return  afVal;
        }
        long divisor = 1;
        switch (ruleType) {
            case "Day":
                // 一天毫秒数
                divisor = 24 * 60 * 60 * 1000;
                afVal = String.valueOf(DateUtil.parse(bfVal).getTime() / divisor);
                break;
            case "Hour":
                // 1小时毫秒数
                divisor = 60 * 60 * 1000;
                afVal = String.valueOf(DateUtil.parse(bfVal).getTime() / divisor);
                break;
            case "Minute":
                // 一分钟毫秒数
                divisor = 60 * 1000;
                afVal = String.valueOf(DateUtil.parse(bfVal).getTime() / divisor);
                break;
            case "String":
                afVal = "\"" + bfVal + "\"";
                break;
            default:
                afVal = bfVal;
                break;
        }
        return afVal;
    }

    private String getKeyWordsfrom(String expressions){
        String res = "";
        Set<String> stringSet = new HashSet<>();
        List<String> list = handleRuleExpressions(expressions);
        List<ContraindicationItemRuleEntity> contraindicationItemRuleEntities = contraindicationItemRuleMapper.selectByExpressions(list);
        for (ContraindicationItemRuleEntity contraindicationItemRuleEntity : contraindicationItemRuleEntities){
            /*if (!StringUtils.isEmpty(contraindicationItemRuleEntity.getDataSource1())){
                SdsStandSourceEntity source1 = sdsStandSourceMapper.selectById(contraindicationItemRuleEntity.getDataSource1());
                stringSet.add(source1.getSourceDesc());
            }
            if (!StringUtils.isEmpty(contraindicationItemRuleEntity.getDataSource2())){
                SdsStandSourceEntity source2 = sdsStandSourceMapper.selectById(contraindicationItemRuleEntity.getDataSource2());
                stringSet.add(source2.getSourceDesc());
            }*/

        }
        if (stringSet.size() > 0){
            res = String.join(", ", stringSet);
        }
        return res;
    }

}
